package com.zz.common.tools;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.zz.common.tools.BaseLruCache.BitmapLruCache;
import com.zz.common.tools.box.tools.IconBox;
import com.zz.common.tools.box.tools.IconBox.OnLoadIconListener;
import com.zz.common.utils.FileUtil;
import com.zz.common.utils.ImageUtil;
import com.zz.common.utils.ZLog;

import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Message;

public class ImageLoader implements Callback {
	public static final int ACTION_IMAGE_LOADER = 10086;
	
	public interface IUrlLocalFilePathCreator {
		public String createLocalFilePathForUrl(String url);
	}
	
	private static final String TAG = "ImageLoader";
	private static BitmapLruCache sCache = new BitmapLruCache(2 * 1024 * 1024);		//2M���ڼ���ͼƬ
	
	private final WeakReferenceHandler mHandler;
	private IUrlLocalFilePathCreator mCreator;
	/*
	 * 
	 */
	public interface OnFinishLoadingListener {
		public void onFinish(int errCode, IconFlinger flinger);
	}
	
	/*
	 *  
	 */
	public class IconToken {
		public String mUrl;
		public Object mUserData;
		private Object mListener;
		public int mTaskId;
		private boolean mIsLocal;
		
		public IconToken(String url, Handler listener, Object userData) {
			mUrl = url;
			mListener = listener;
			mUserData = userData;
			setIsLocal();
		}
		
		public IconToken(String url, OnFinishLoadingListener listener, Object userData) {
			mUrl = url;
			mListener = listener;
			mUserData = userData;
			setIsLocal();
		}
		private void setIsLocal() {
			mIsLocal = (!mUrl.startsWith("http://") && !mUrl.startsWith("https://"));
		}
	}
	
	/*
	 * 
	 */
	
	protected ImageLoader(IUrlLocalFilePathCreator creator) {
		mHandler = new WeakReferenceHandler(this);
		mCreator = creator;
	}
	
	public class IconFlinger {
		public Bitmap mIcon;
		public IconToken mToken;
		
		public IconFlinger(IconToken token) {
			mToken = token;
		}
		
		void sendResult(Bitmap bitmap, int errCode) {
			Object listener = mToken.mListener;
			if(null != listener) {
				mIcon = bitmap;
				if(Handler.class.isInstance(listener)) {
					Message msg = ((Handler)listener).obtainMessage(ACTION_IMAGE_LOADER, errCode, 0, this);
					
					if(String.class.isInstance(mToken.mUserData)) {
						Bundle b = new Bundle();
						b.putString("userData", (String)mToken.mUserData);
						msg.setData(b);
					}
					msg.sendToTarget();
				} else {
					mHandler.post(new FlingerRunner(this, errCode));
				}
				
				ZLog.d(TAG, "sendResult: " +mIcon + ", "+ mToken.mListener + ", " + mToken.mUserData + ",  " + mToken.mUrl);
			}
		}
	}
	
	/*
	 * 
	 */
	public Map<String, List<IconFlinger>> mFlingers = new Hashtable<String, List<IconFlinger> >();
	
	/*
	 * 
	 */
	public void cancelLoadIcon(IconToken token) {
		if(null == token) {
			return;
		}
		ZLog.d(TAG, "cancelLoadIcon: " + token.mListener + ", " + token.mUserData + ",  " + token.mUrl);
		synchronized (mFlingers) {
			List<IconFlinger> list = mFlingers.get(token.mUrl);
			if(null != list) {
				int i;
				for(i = 0; i<list.size(); ) {
					IconFlinger flinger = list.get(i);
					if(flinger.mToken == token) {
						list.remove(i);
					} else {
						i++;
					}
				}
				if(0 == list.size()) {
					mFlingers.remove(token.mUrl);
					IconBox.cancel(token.mTaskId);
				}
			}
		}
	}
	
	public void cancelAll() {
		synchronized (mFlingers) {
			Iterator<List<IconFlinger>> temp = mFlingers.values().iterator();
			while(temp.hasNext()) {
				List<IconFlinger> list = temp.next();
				IconBox.cancel(list.get(0).mToken.mTaskId);
			}
			mFlingers.clear();
		}
	}
	
	public Bitmap getIconFromCache(String iconUrl) {
		Bitmap map = getIconFromLocalCache(iconUrl, true);
		return map;
	}
	
	public IconToken loadIcon(String url, Handler listener, Object userData) {
		return loadIcon(new IconToken(url, listener, userData), true);
	}
	
	public IconToken loadIcon(String url, OnFinishLoadingListener listener, Object userData) {
		return loadIcon(new IconToken(url, listener, userData), false);
	}
	
	@Override		//Handler.Callback
	public boolean handleMessage(Message msg) {
		return false;
	}
	
	private IconToken loadIcon(IconToken token, boolean includeSDCard) {
		ZLog.d(TAG, "loadIcon: " + token.mUrl + ", " + token.mUserData + ",  " + token.mListener);
		String url = token.mUrl;
		if(null == url) {
			return null;
		}
		
		//��RAM�����м���
		IconFlinger flinger = new IconFlinger(token);
		Bitmap b = getIconFromLocalCache(url, includeSDCard);
		if(null != b) {
			flinger.sendResult(b, 0);
			return flinger.mToken;
		}
		
		String localPath = null;
		if(token.mIsLocal) {
			localPath = token.mUrl;
		} else {
			localPath = mCreator.createLocalFilePathForUrl(url);
		}
		
		//�ӷ�������ȡ
		synchronized (mFlingers) {
			List<IconFlinger> flingerList = mFlingers.get(url);
			if(null == flingerList) {
				flingerList = new ArrayList<IconFlinger>();
				mFlingers.put(url, flingerList);
				IconBox box = new IconBox();
				
				flinger.mToken.mTaskId = box.loadIcon(url, localPath, new OnLoadIconListener() {

					@Override
					public void onFailed(String iconUrl, int errCode,
							IconBox box) {
						ZLog.d(TAG, "failed loadIcon: " + iconUrl);
						List<IconFlinger> list = mFlingers.get(iconUrl);
						if(null != list) {
							for(IconFlinger flinger: list) {
								flinger.sendResult(null, errCode);
							}
						}
						mFlingers.remove(iconUrl);
					}

					@Override
					public void onSuccess(String iconUrl, String localPath,
							IconBox box) {
						ZLog.d(TAG, "success loadIcon: " + iconUrl);
						List<IconFlinger> list = mFlingers.get(iconUrl);
						Bitmap b = ImageUtil.decodeLocalFile(localPath, 0);
						int errCode = -1;
						if(null != b) {
							errCode = 0;
							addToCache(iconUrl, b);
						}
						if(null != list) {
							for(IconFlinger flinger: list) {
								flinger.sendResult(b, errCode);
							}
						}
						mFlingers.remove(iconUrl);
					}
					
				});
			} else {
				flinger.mToken.mTaskId = flingerList.get(0).mToken.mTaskId;
			}
			flingerList.add(flinger);
		}
		
		return flinger.mToken;
	}
	
	private Bitmap getIconFromLocalCache(String iconUrl, boolean includeSDCard) {
		if(null == iconUrl) {
			return null;
		}
		Bitmap map = sCache.get(iconUrl);
		 return map;
	}
	
	private void addToCache(String iconUrl, Bitmap b) {
		sCache.put(iconUrl, b);
	}
	
	private class FlingerRunner implements Runnable {
		
		private IconFlinger mFlinger;
		private int mErrCode;
		
		private FlingerRunner(IconFlinger flinger, int errCode) {
			mFlinger = flinger;
			mErrCode = errCode;
		}

		@Override
		public void run() {
			((OnFinishLoadingListener)mFlinger.mToken.mListener).onFinish(mErrCode, mFlinger);
			mFlinger = null;
		}
		
	}
}


